iT邦幫忙

2025 iThome 鐵人賽

DAY 2
0

什麼是像素

我們可以想像眼前有一幅馬賽克拼貼畫,它由數萬個彩色磁磚構成,而對於數位影像來說,這些彩色磁磚所指的就是像素 (pixel)。
一張數位影像,本質上是由許多像素所組成的二維矩陣。每個像素都帶有一個值,其代表該位置的色彩資訊。
https://ithelp.ithome.com.tw/upload/images/20250812/20178100nBrz385RYC.jpg
https://ithelp.ithome.com.tw/upload/images/20250812/201781006w1JGlouFj.jpg

色彩空間

如何表示顏色

既然每個像素都儲存著顏色資訊,那我們該如何用數字來描述「紅色」、「天空的藍色」或「草地的綠色」呢?這就是色彩空間 (color space) 的任務。
色彩空間定義了一套規則,用來將顏色量化成數字。接下來,我們來認識幾個在電腦視覺中至關重要的色彩空間。

RGB 色彩空間

我們最熟悉的色彩空間。它基於加色模型,就像舞台上的紅、綠、藍三盞聚光燈,透過調整各自的亮度,可以混合出光譜中的各種顏色。

  • 在數位影像中,一個像素的顏色通常由三個數值表示:(R, G, B)。
  • 對於一個 8-bit 影像,每個數值的範圍是 0 至 255,0 代表最暗、255 代表最亮。

舉例來說:

  1. (255, 0, 0) 代表純紅色
  2. (0, 255, 0) 代表純綠色
  3. (0, 0, 255) 代表純藍色
  4. (0, 0, 0) 代表黑色
  5. (255, 255, 255) 代表白色

BGR 色彩空間

與 RGB 色彩空間的概念相同,但順序變為藍、綠、紅色。由於一些歷史因素,OpenCV 所採用的是 BGR 色彩空間
因此要注意的是,當使用 Matplotlib 等其他套件時,我們需要手動地將 BGR 轉換回 RGB 色彩空間,以免顏色異常。

HSV 色彩空間

跟 RGB 與 BGR 色彩空間相比,更接近人類感知顏色的方式。HSV 三個字母分別代表:

  • 色相 Hue:代表顏色本身,如紅色、黃色、藍色,通常由一個 360 度的圓環表示。要注意的是,OpenCV 的色相取值範圍為 0 ~ 180。
  • 飽和度 Saturation:代表顏色的「純度」或「鮮豔度」,越低越接近灰色。
  • 明度 Value: 代表顏色的「亮度」,越高越亮,越低越接近黑色。

XYZ 與 L*U*V* 色彩空間

XYZ 是一個基礎的、設備無關的色彩空間,試圖將所有人類可見的顏色都包含在內。其中 Y 分量直接對應顏色的亮度。
L*U*V* 色彩空間則是由 XYZ 轉換而來,在這個色彩空間內,兩點之間的數學距離,能很好地對應到人類視覺感知到的顏色差異。

OpenCV 色彩轉換

在 OpenCV 中,我們可以使用 cv2.cvtColor() 來轉換色彩空間。

import cv2
import numpy as np

img_path = 'flower.jpg'
bgr_image = cv2.imread(img_path)

# --- 1. 查看影像的基本屬性 ---
print(f"圖片的形狀 (高, 寬, 通道數): {bgr_image.shape}")
print(f"圖片的資料類型: {bgr_image.dtype}")

top_left_pixel = bgr_image[0, 0]
print(f"左上角像素的 BGR 值: {top_left_pixel}")

# --- 2. 分離 B, G, R 通道 ---
# 使用 cv2.split() 將三個通道分離
b, g, r = cv2.split(bgr_image)

# 為了能正確顯示單一通道(它們是灰階的),我們可以建立一個全黑的畫布,再把通道放上去
h, w, _ = bgr_image.shape
zeros = np.zeros((h, w), dtype="uint8")

# cv2.merge() 是 cv2.split() 的反向操作
blue_channel_img = cv2.merge([b, zeros, zeros])
green_channel_img = cv2.merge([zeros, g, zeros])
red_channel_img = cv2.merge([zeros, zeros, r])

cv2.imshow("Original Image", bgr_image)
cv2.imshow("Blue Channel", blue_channel_img)
cv2.imshow("Green Channel", green_channel_img)
cv2.imshow("Red Channel", red_channel_img)

# --- 3. 色彩空間轉換:BGR -> HSV ---
hsv_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2HSV)

# 分離 HSV 通道來觀察
h, s, v = cv2.split(hsv_image)

cv2.imshow("HSV Image", hsv_image) # HSV 直接顯示顏色會很奇怪
cv2.imshow("Hue Channel", h)
cv2.imshow("Saturation Channel", s)
cv2.imshow("Value (Brightness) Channel", v)

# --- 4. 其他色彩空間轉換 ---
# BGR -> XYZ
xyz_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2XYZ)
# BGR -> L*U*V*
luv_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2Luv) # L*U*V* 直接顯示顏色會很奇怪

# --- 5. 儲存圖片 ---
cv2.imwrite('original_image.jpg', bgr_image)
cv2.imwrite('blue_channel.jpg', blue_channel_img)
cv2.imwrite('green_channel.jpg', green_channel_img)
cv2.imwrite('red_channel.jpg', red_channel_img)
cv2.imwrite('hsv_image.jpg', hsv_image)
cv2.imwrite('hue_channel.jpg', h)
cv2.imwrite('saturation_channel.jpg', s)
cv2.imwrite('value_channel.jpg', v)
cv2.imwrite('xyz_image.jpg', xyz_image)
cv2.imwrite('luv_image.jpg', luv_image)

print("\n已完成所有影像處理。")
cv2.waitKey(0)
cv2.destroyAllWindows()

Original Image
https://ithelp.ithome.com.tw/upload/images/20250812/20178100a74swsDBpV.jpg
Red Channel
https://ithelp.ithome.com.tw/upload/images/20250812/20178100ljCVWspSXy.jpg
Green Channel
https://ithelp.ithome.com.tw/upload/images/20250812/20178100vcBU5puZw8.jpg
Blue Channel
https://ithelp.ithome.com.tw/upload/images/20250812/20178100w8mYgtevmk.jpg
Hue
https://ithelp.ithome.com.tw/upload/images/20250812/20178100YKj0dAqfcz.jpg
Saturation
https://ithelp.ithome.com.tw/upload/images/20250812/201781007qV4OcRsqK.jpg
Value
https://ithelp.ithome.com.tw/upload/images/20250812/20178100u0qPmkoEFd.jpg
HSV
https://ithelp.ithome.com.tw/upload/images/20250812/20178100Fzi5GOrmoE.jpg
XYZ
https://ithelp.ithome.com.tw/upload/images/20250812/20178100xRjUphF6Ee.jpg
L*U*V*
https://ithelp.ithome.com.tw/upload/images/20250812/20178100xZfyEJTEN9.jpg

參數說明

cv2.cvtColor(Image, ColorSpace)

  • Image:要顯示的圖片變數
  • ColorSpace:要轉換的色彩空間,如 cv2.COLOR_BGR2HSV 代表 BGR 轉為 HSV

cv2.split(Image, Mv)

  • Image:要分拆的圖片變數
  • Mv:指定的拆分通道(可選)

cv2.merge([Channel1, Channel2, Channel3, ...])

  • Channel:要合併的單通道影像

cv2.imwrite(ImgPath, Image, Quality)

  • ImgPath:圖片儲存的路徑與檔名
  • Image:要儲存的圖片
  • Quality:壓縮品質設定(可選)

額外說明

HSV 與 L*U*V* 直接顯示顏色很奇怪的原因是:顯示器會將 HSV (L*U*V*) 的數值誤解為 RGB 數值,且 L*U*V* 的 U 與 V 可能為負或超過 255,所以通常建議 HSV (L*U*V*) 三個通道分開來查看。


上一篇
Day 1 - 人類與電腦視覺入門
下一篇
Day 3 - 曝光與直方圖
系列文
從0開始:傳統圖像處理到深度學習模型23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言